//
// Created by ziya on 22-8-20.
//
#include "../../include/common.h"
#include "../../include/core/coroutine.h"
#include "../../include/core/sched.h"

extern coroutine_t* coroutines[TASK_SIZE];

coroutine_t* current_coroutine = NULL;

static coroutine_t* find_ready_minithread() {
    coroutine_t* next = NULL;

    // 判断是不是所有任务都被调度了一轮
    bool is_all_zero = true;
    bool is_null = true;

    for (int i = 1; i < TASK_SIZE; ++i) {
        coroutine_t* minithread = coroutines[i];

        if (NULL == minithread) continue;

        is_null = false;

        if (0 != minithread->counter) {
            is_all_zero = false;
            break;
        }
    }

    // 如果没有任务需要调度，is_all_zero也为true，排除这种情况
    if (!is_null && is_all_zero)  goto reset;

    // 找到待调度的任务
    for (int i = 1; i < TASK_SIZE; ++i) {
        coroutine_t* coroutine = coroutines[i];

        if (NULL == coroutine) {
            continue;
        }

        if (current_coroutine == coroutine && COROUTINE_RUNNING == coroutine->state) {
            coroutine->state = COROUTINE_READY;
        }

        if (COROUTINE_READY != coroutine->state) continue;

        if (NULL == next) {
            next = coroutine;
        } else {
            if (coroutine->counter > next->counter) {
                next = coroutine;
            }
        }
    }

    if (NULL == next) {
        next = coroutines[0];
    }

    return next;

    /**
     * 如果所有任务的counter都为0,代表所有任务都被调度了一轮
     * 重新赋值
     */
reset:
    if (is_all_zero) {
        for (int i = 1; i < TASK_SIZE; ++i) {
            coroutine_t* tmp = coroutines[i];

            if (NULL == tmp) continue;

            tmp->counter = tmp->priority;
        }

        // 重新设置counter后，再次查找可调度的任务
        return find_ready_minithread();
    }
}

void sched() {
    coroutine_t * ready_coroutine;

    if (NULL != current_coroutine) {
        if (COROUTINE_SLEEPING != current_coroutine->state && COROUTINE_BLOCKED != current_coroutine->state) {
            current_coroutine->state = COROUTINE_READY;
        }

        current_coroutine = NULL;
    }

    ready_coroutine = find_ready_minithread();

    current_coroutine = ready_coroutine;

    ready_coroutine->state = COROUTINE_RUNNING;

    __asm__(
        "mov %%rsp, 0(%%rcx);"      // 保存栈
        "mov %%rcx, %%rsp;"         // 切栈
        "callq %%rax;"              // 协程的执行流
        "pop %%rsp;"                // 恢复rsp
        "callq %%rbx;"              // coroutine_exit()
        ""::"a"(ready_coroutine->fun), "c"(ready_coroutine->esp3 - 8), "d"(current_coroutine), "b"(coroutine_exit):"memory"
    );
}

void do_timer() {
    if (NULL == current_coroutine) {
        sched();
    }

    if((NULL != current_coroutine) && (current_coroutine->counter > 0)) {
        current_coroutine->counter--;
        return;
    }

    sched();
}